using System.Collections;
using System.Linq;
using UnityEngine;
using System;
using System.Net;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Text;
using VRCPRServer.Models;
using CPRMulti.Tools;

namespace VRCPRServer.NetWork
{
    /// <summary>
    /// 学生modle
    /// </summary>
    public class StudentM {
        public void Reset() { }
    }
    [Serializable]
    public class TcpNetManager
    {
        private static readonly object lookObj = new object();
        private static TcpNetManager instance;
        private bool isCanReceiveData = true;
        private System.Threading.Tasks.Task task;
        private ManualResetEvent ResetEvent = new ManualResetEvent(false);
        public Action<string> MsgChangeEvent;

        public Action<IPEndPoint> isConnectedEvent;
        public Action<IPEndPoint> isDisConnectedEvent;
        /// <summary>
        /// 操作是否停止
        /// </summary>
        public bool IsCanReceiveData
        {
            get { lock (instance) { return isCanReceiveData; } }
            set
            {
                lock (instance)
                {
                    isCanReceiveData = value;
                }
            }
        }

        /// <summary>
        /// 连接服务端的Socket集合
        /// </summary>
        public Dictionary<IPEndPoint, AsyncTcpClient> SocketDic;

        /// <summary>
        /// 客户端接收到的数据集合
        /// </summary>
        public Dictionary<IPEndPoint, DataBuffer> BufferDic;

        /// <summary>
        /// 学员数据集合
        /// </summary>
        public Dictionary<IPEndPoint, StudentM> StudentDic;

        /// <summary>
        /// 实例
        /// </summary>
        public static TcpNetManager Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (lookObj)
                    {
                        if (instance == null)
                        {
                            instance = new TcpNetManager();
                        }
                    }
                }
                return instance;
            }
        }

        // Use this for initialization
        private TcpNetManager()
        {
            BufferDic = new Dictionary<IPEndPoint, DataBuffer>();
            SocketDic = new Dictionary<IPEndPoint, AsyncTcpClient>();
            StudentDic = new Dictionary<IPEndPoint, StudentM>();
            heartTime = DateTime.Now;
            ThreadTimer();
        }


        /// <summary>
        /// 添加客户端连接（连接模拟人Socket）
        /// </summary>
        /// <param name="remoteEP">远端节点</param>
        /// <returns>返回是否连接成功</returns>
        public bool AddSocketClient(IPEndPoint remoteEP)
        {
            if (remoteEP == null) return false;

            if (SocketDic.TryGetValue(remoteEP, out AsyncTcpClient client))
            {
                //Tools.Loom.QueueOnMainThread(() =>
                //{
                //    MsgChangeEvent?.Invoke($"{remoteEP} 已连接");
                //});
                Debug.Log($"{remoteEP}----------------------这个硬件已连接");
                return false;
            }
            AsyncTcpClient tcpClient = new AsyncTcpClient(remoteEP);
            tcpClient.ServerConnected += TcpClient_ServerConnected;
            tcpClient.ServerDisConnected += TcpClient_ServerDisConnected;
            tcpClient.DatagramReceive += TcpClient_DatagramReceive;
            tcpClient.ServerExceptionOccurred += TcpClient_ServerExceptionOccurred;
            tcpClient.Connect();
            Debug.Log($"{remoteEP}-------------------开始连接");
            //在这里提前进行创建  StudentM

            return tcpClient.IsConnected;
        }

        /// <summary>
        /// 移除客户端连接（断开并移除模拟人Socket）
        /// </summary>
        /// <param name="remoteEP">远端节点</param>
        /// <returns>返回是否移除成功</returns>
        public bool RemoveSocketClient(IPEndPoint remoteEP)
        {
            if (remoteEP == null) return false;

            lock (SocketDic)
            {
                if (SocketDic.TryGetValue(remoteEP, out AsyncTcpClient tcpClient))
                {
                    tcpClient.Dispose();
                    return true;
                }
                else
                {
                    MonoBehaviour.print("SocketDic.TryGetValue is false");
                }
            }

            return false;
        }

        /// <summary>
        /// 向模拟人发送连接指令
        /// </summary>
        /// <param name="tcpClient"></param>
        private void SendStartCommand(AsyncTcpClient tcpClient)
        {
            if (tcpClient == null || !tcpClient.IsConnected || (task != null && !task.IsCompleted)) return;

            task = new System.Threading.Tasks.Task(() =>
            {
                Thread.Sleep(500);
                tcpClient.Send(Command.Connect);
                Thread.Sleep(200);
                tcpClient.Send(Command.Start);
            });
            task.Start();
        }

        /// <summary>
        /// 客户端连接上模拟人服务端消息通知
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TcpClient_ServerConnected(object sender, TcpServerConnectedEventArgs e)
        {
            AsyncTcpClient tcpClient = sender as AsyncTcpClient;
            SendStartCommand(tcpClient);
            if (!SocketDic.ContainsKey(tcpClient.RemoteIPEndPoint))
                SocketDic.Add(tcpClient.RemoteIPEndPoint, tcpClient);

            if (!BufferDic.ContainsKey(tcpClient.RemoteIPEndPoint))
                BufferDic.Add(tcpClient.RemoteIPEndPoint, new DataBuffer(20480, 7));
            if (!StudentDic.ContainsKey(tcpClient.RemoteIPEndPoint))
                StudentDic.Add(tcpClient.RemoteIPEndPoint, new StudentM());
            Debug.Log($"客户端连接上模拟人：{DateTime.Now} : {tcpClient.RemoteIPEndPoint}");
           Loom.QueueOnMainThread(() =>
            {
                isConnectedEvent?.Invoke(tcpClient.RemoteIPEndPoint);
                MsgChangeEvent?.Invoke($"客户端连接上模拟人：{DateTime.Now} : {tcpClient.RemoteIPEndPoint}");
            });
        }

        /// <summary>
        /// 客户端断开连接模拟人服务端消息通知
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TcpClient_ServerDisConnected(object sender, TcpServerDisconnectedEventArgs e)
        {
            AsyncTcpClient tcpClient = sender as AsyncTcpClient;

            lock (SocketDic)
            {
                if (tcpClient != null && SocketDic.Remove(tcpClient.RemoteIPEndPoint))
                {
                    BufferDic.Remove(tcpClient.RemoteIPEndPoint);
                    StudentDic.Remove(tcpClient.RemoteIPEndPoint);
                    tcpClient.ServerConnected -= TcpClient_ServerConnected;
                    tcpClient.ServerDisConnected -= TcpClient_ServerDisConnected;
                    tcpClient.DatagramReceive -= TcpClient_DatagramReceive;
                    tcpClient.ServerExceptionOccurred -= TcpClient_ServerExceptionOccurred;
                }
            }

            Loom.QueueOnMainThread(() =>
            {
                isDisConnectedEvent?.Invoke(tcpClient.RemoteIPEndPoint);
                MsgChangeEvent?.Invoke($"断开连接： {tcpClient.RemoteIPEndPoint}");
            });
        }

        /// <summary>
        /// 客户端连接模拟人服务端异常信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TcpClient_ServerExceptionOccurred(object sender, TcpServerExceptionOccurredEventArgs e)
        {
            AsyncTcpClient tcpClient = sender as AsyncTcpClient;

            Loom.QueueOnMainThread(() =>
            {
                MsgChangeEvent?.Invoke($"{tcpClient.RemoteIPEndPoint} 连接异常: {e.Exception}");
            });
        }

        /// <summary>
        /// 接收CPR模拟人服务端数据
        /// </summary>
        /// <param name="sender">客户端</param>
        /// <param name="e">接收数据事件</param>
        private void TcpClient_DatagramReceive(object sender, TcpDatagramReceivedEventArgs<byte[]> e)
        {
            AsyncTcpClient tcpClient = sender as AsyncTcpClient;
            if (!IsCanReceiveData || BufferDic == null) return;

            if (BufferDic.TryGetValue(tcpClient.RemoteIPEndPoint, out DataBuffer dataBuffer))
            {
                dataBuffer.WriteBuffer(e.Datagram);
            }
            else
            {
                BufferDic.Add(tcpClient.RemoteIPEndPoint, new DataBuffer(20480, 7));
            }
        }

        #region 定时发送数据
        private DateTime heartTime;
        private DateTime sendVRTime;
        private CancellationTokenSource tokenSource = new CancellationTokenSource();

        private void ThreadTimer()
        {
            sendVRTime = heartTime = DateTime.Now;
            CancellationToken cancellationToken = tokenSource.Token;

            System.Threading.Tasks.Task.Run(() =>
            {
                try
                {
                    while (true)
                    {
                        if (cancellationToken.IsCancellationRequested) return;
                        Thread.Sleep(1);

                        if (Math.Abs(DateTime.Now.Millisecond / 10 - sendVRTime.Millisecond / 10) > 2)
                        {
                            sendVRTime = DateTime.Now;

                            if (isCanReceiveData)
                            {
                                //sendDataToVR.SendData();
                            }
                        }

                        if (Math.Abs(DateTime.Now.Second - heartTime.Second) >= 1)
                        {
                            heartTime = DateTime.Now;
                            //sendDataToVR.SendHeart();
                            SendHeart();
                        }

                        ResetEvent.WaitOne();
                    }
                }
                catch (Exception e)
                {
                    MonoBehaviour.print(e);
                }

            }, cancellationToken).ContinueWith((t) => { t.Dispose(); Debug.Log("销毁完成"); }); ;
            ResetEvent.Set();
        }
        #endregion

        #region 心跳包 / 重连 / 发送数据
        /// <summary>
        /// 服务端发送心跳包
        /// </summary>
        private void SendHeart()
        {
            if (SocketDic == null || SocketDic.Count < 1) return;
            for (int i = 0; i < SocketDic.Count; i++)
            {
                AsyncTcpClient tcpClient = SocketDic.ElementAt(i).Value;
                if (tcpClient != null && tcpClient.IsConnected)
                {
                    SendBytes(Command.Heart);
                }
                else
                {
                    //tcpClient.ReConnect();
                }
            }
        }

        /// <summary>
        /// 向模拟人发送数据
        /// </summary>
        /// <param name="data"></param>
        public void SendBytes(byte[] data)
        {
            if (data == null) return;

            int length = SocketDic.Count;
            for (int i = 0; i < length; i++)
            {
                lock (SocketDic)
                {
                    AsyncTcpClient tcpClient = SocketDic.ElementAt(i).Value;
                    if (tcpClient != null && tcpClient.IsConnected)
                    {
                        tcpClient.Send(data);
                    }
                }
            }
        }
        #endregion

        public void OnApplicationQuit()
        {
            for (int i = 0; i < SocketDic.Count; i++)
            {
                AsyncTcpClient tcpClient = SocketDic.ElementAt(i).Value;
                if (tcpClient != null)
                {
                    tcpClient.Dispose();
                }
            }

            ResetEvent.Reset();
            tokenSource.Cancel();
            //sendDataToVR.Close();
        }
        public void ResetAllData() {
            foreach (var item in BufferDic)
            {
                item.Value.clear();
            }
            foreach (var item in StudentDic)
            {
                item.Value.Reset();
            }
        }
        /// <summary>
        /// 关闭所有连接，并释放相关资源
        /// </summary>
        public void Closed()
        {
            System.Threading.Tasks.Task.Run(() =>
            {
                SendBytes(Command.Stop);
                //sendDataToVR.SendStateInfo(Command.ConnectState, 0x00, new byte[] { 0x03, 0x00, 0x00, 0x00 });
                for (int i = SocketDic.Count; i > 0; i--)
                {
                    AsyncTcpClient asyncTcpClient = SocketDic.ElementAt(i - 1).Value;
                    asyncTcpClient.Dispose();
                    lock (SocketDic)
                    {
                        SocketDic.Remove(asyncTcpClient.RemoteIPEndPoint);
                        BufferDic.Remove(asyncTcpClient.RemoteIPEndPoint);
                        StudentDic.Remove(asyncTcpClient.RemoteIPEndPoint);
                    }
                }
            }).Wait();
        }
    }
}
